package com.yunyao.framework.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yunyao.common.constant.enums.DataDeletedStatus;
import com.yunyao.common.core.BaseContext;
import com.yunyao.common.core.UserInfoRequest;
import com.yunyao.common.dto.MaterialCategoryDto;
import com.yunyao.common.dto.MaterialDto;
import com.yunyao.common.web.util.PageResult;
import com.yunyao.common.web.util.YResult;
import com.yunyao.dao.model.BamuMaterial;
import com.yunyao.dao.model.BamuMaterialCategory;
import com.yunyao.dao.service.bamu.IBamuMaterialCategoryService;
import com.yunyao.dao.service.bamu.IBamuMaterialService;
import com.yunyao.framework.service.MaterialService;
import com.yunyao.framework.vo.material.MaterialCategoryTreeVO;
import com.yunyao.framework.vo.material.MaterialVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author xingjishuai
 * @date 2024-07-24
 */
@Slf4j
@Service
public class MaterialServiceImpl implements MaterialService {
    @Autowired
    private IBamuMaterialService iBamuMaterialService;
    @Autowired
    private IBamuMaterialCategoryService iBamuMaterialCategoryService;

    @Override
    public YResult<PageResult<MaterialVO>> pageList(MaterialDto materialDto) {
        // 构建查询条件
        Long pageIndex = materialDto.getPageIndex();
        Long pageSize = materialDto.getPageSize();
        String materialCode = materialDto.getMaterialCode();
        String materialName = materialDto.getMaterialName();
        String materialSpecifications = materialDto.getMaterialSpecifications();
        String materialCategoryId = materialDto.getMaterialCategoryId();
        IPage<BamuMaterial> materialPage = iBamuMaterialService.pageList(pageIndex, pageSize,
                materialCode, materialName, materialSpecifications, materialCategoryId);

        // 处理查询结果
        if (CollectionUtils.isEmpty(materialPage.getRecords())) {
            return YResult.success(new PageResult<>());
        }

        // 转换为VO对象列表
        List<MaterialVO> voList = daoToVoList(materialPage.getRecords());

        // 返回分页结果
        return YResult.success(new PageResult<>(voList, materialPage.getCurrent(),
                materialPage.getSize(), materialPage.getPages(), materialPage.getTotal()));
    }

    /**
     * 根据材料类别DTO获取材料类别的树形结构
     *
     * @param materialCategoryDto 材料类别DTO，包含查询条件
     * @return 返回处理结果，包括材料类别的树形结构列表
     */
    @Override
    public YResult<List<MaterialCategoryTreeVO>> categoryTree(MaterialCategoryDto materialCategoryDto) {
        // 获取当前用户信息，用于查询特定租户下的材料类别
        UserInfoRequest userInfo = BaseContext.getUserInfo();
        // 租户ID，用于限定查询特定租户下的材料类别
        String tenantId = userInfo.getTenantId();
        // 父类别ID，用于查询特定父类别下的子类别
        String parentId = StringUtils.isBlank(materialCategoryDto.getParentId()) ?
                BigDecimal.ZERO.toString() :
                materialCategoryDto.getParentId();
        // 类别名称，用于模糊查询
        String categoryName = materialCategoryDto.getCategoryName();
        // 构建查询条件
        LambdaQueryWrapper<BamuMaterialCategory> queryWrapper =
                new LambdaQueryWrapper<BamuMaterialCategory>()
                        .eq(BamuMaterialCategory::getParentId, parentId)
                        .like(StringUtils.isNotBlank(categoryName),
                                BamuMaterialCategory::getCategoryName, categoryName)
                        .eq(BamuMaterialCategory::getTenantId, tenantId)
                        .eq(BamuMaterialCategory::getIsDeleted, DataDeletedStatus.NO.getType())
                        .orderByAsc(BamuMaterialCategory::getSort)
                        .orderByDesc(BamuMaterialCategory::getId);
        // 执行查询，获取材料类别列表
        List<BamuMaterialCategory> materialCategoryList =
                iBamuMaterialCategoryService.list(queryWrapper);
        // 如果查询结果为空，返回成功结果，但列表为空
        if (CollectionUtils.isEmpty(materialCategoryList)) {
            return YResult.success(new ArrayList<>());
        }
        // 将查询结果转换为树形结构的VO列表，并返回成功结果
        return YResult.success(categoryTreeDaoToVoList(materialCategoryList));
    }


    /**
     * 将材料分类列表从Dao层对象转换为VO层对象
     *
     * 本方法使用Java 8的Stream API对Dao层获取的材料分类列表进行转换，
     * 每个Dao层对象通过调用categoryTreeDaoToVo方法转换为对应的VO层对象，
     * 最终收集并返回一个包含所有转换后VO对象的列表
     *
     * @param materialCategoryList 从Dao层获取的材料分类列表
     * @return 转换后的VO层材料分类列表
     */
    private List<MaterialCategoryTreeVO> categoryTreeDaoToVoList(List<BamuMaterialCategory> materialCategoryList) {
        return materialCategoryList.stream()
                                   .map(this::categoryTreeDaoToVo)
                                   .collect(Collectors.toList());
    }

    /**
     * 将数据库访问层的类别信息转换为视图对象
     * 此方法的目的是为了将从数据库中查询到的类别信息转换为一个树状结构的视图对象，以便前端展示
     * 它不仅包含了基本的属性复制，还提供了判断类别下是否有子类别的功能
     *
     * @param bamuMaterialCategory 数据库访问层的类别实体，代表了一个具体的材料类别
     * @return 返回一个 MaterialCategoryTreeVO 对象，包含了转换后的类别信息和是否有子类别的标志
     */
    private MaterialCategoryTreeVO categoryTreeDaoToVo(BamuMaterialCategory bamuMaterialCategory) {
        // 初始化视图对象
        MaterialCategoryTreeVO materialCategoryTreeVO = new MaterialCategoryTreeVO();
        // 复制数据库实体的属性到视图对象
        BeanUtils.copyProperties(bamuMaterialCategory, materialCategoryTreeVO);
        // 获取当前类别的ID
        String id = bamuMaterialCategory.getId();
        // 查询数据库，统计当前类别下子类别的数量
        long count = iBamuMaterialCategoryService.countById(id);
        // 根据子类别数量设置视图对象的是否有子类别的标志
        materialCategoryTreeVO.setHasChildren(count > 0);
        // 返回转换后的视图对象
        return materialCategoryTreeVO;
    }

    /**
     * 将数据访问对象列表转换为视图对象列表
     *
     * @param records 数据访问对象列表，包含从数据库中查询到的材料信息
     * @return 视图对象列表，用于展示或进一步处理
     *
     * 说明：本方法使用Java 8的Stream API对数据访问对象列表进行转换，目的是为了将数据库查询结果
     * 转换为更方便操作和展示的视图对象格式
     */
    private List<MaterialVO> daoToVoList(List<BamuMaterial> records) {
        return records.stream().map(this::daoToVo).collect(Collectors.toList());
    }

    /**
     * 将Material实体类对象转换为MaterialVO对象
     *
     * @param bamuMaterial BamuMaterial实体类对象，代表数据库中材料信息的映射
     * @return MaterialVO 转换后的MaterialVO对象，用于展示或传输材料信息
     *
     * 说明：本方法主要用途是将从数据库查询到的材料信息（BamuMaterial对象）
     * 转换为可以用于前端展示或其他服务调用的MaterialVO对象。这样做可以
     * 实现数据和展示的解耦，便于维护和扩展。
     */
    private MaterialVO daoToVo(BamuMaterial bamuMaterial) {
        MaterialVO materialVO = new MaterialVO(); // 创建MaterialVO对象实例
        BeanUtils.copyProperties(bamuMaterial, materialVO); // 使用Spring的BeanUtils进行属性复制
        return materialVO; // 返回转换后的MaterialVO对象
    }
}
